
#include "area.h"
#include "avatar.h"
#include "commandTable.h"
#include "commandTable-default.h"
#include "display.h"
#include "handler.h"
#include "room.h"
#include "symphony.h"
#include "world.h"

/*
Cmd::Cmd( void ) {
  name( "" );
  return;
}

bool Cmd::execute( Creature* creature, const std::string& args ) {

  return true;
}
*/

CmdGecho::CmdGecho( void ) {
  name( "gecho" );
  level( GOD );
  syntax( "gecho <message>" );
  return;
}

bool CmdGecho::execute( Creature* creature, const std::string& args ) {
  std::string text = Regex::trim( args );

  for ( std::map<std::string,Avatar*>::iterator it = World::Instance().getAvatars().begin(); it != World::Instance().getAvatars().end(); ++it ) {
    if ( it->second->status() == CONNECTED ) {
      it->second->send( "{%c%s{x", creature->gechoColor(), text.c_str() );
    }
  }

  return true;
}

CmdGet::CmdGet( void ) {
  name( "get" );
  syntax( "syntax: get <object>\n        get all\n        get <object> <container>\n        get all <container>" );
  return;
}

bool CmdGet::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  Object* foo = NULL;
  ObjContainer* container = NULL;
  Object* object = NULL;

  if ( args.empty() ) {
    creature->send( syntax() );
    return false;
  }

  if ( pieces[0] == "all" ) {
    if ( pieces.size() == 1 ) {
      // Get all objects from the room...
      creature->objects().splice( creature->objects().begin(), creature->room()->objects() );
      creature->send( "You grab everything you can find." );
      creature->room()->send( "$p gets some things.", creature );
      return true;
    } else {
      if ( ( foo = creature->findObject( pieces[1] ) ) == NULL ) {
        creature->send( "You don't see that here." );
        return false;
      }
      if ( foo->type() == OTYPE_CONTAINER ) {
        container = (ObjContainer*)foo;
      } else {
        creature->send( "That's not a container." );
        return false;
      }
      if ( container->objects().empty() ) {
        creature->send( "It's empty." );
        return false;
      }
      creature->objects().splice( creature->objects().begin(), container->objects() );
      creature->send( "You take everything out of %s.", container->shortname().c_str() );
      creature->room()->send( "$p gets some things from $o.", creature, container );
      return true;
    }
  }

  if ( pieces.size() == 1 ) {
    if ( ( object = creature->room()->findObject( args ) ) == NULL || creature->canSee( object ) != SEE_NAME ) {
      creature->send( "You don't see that here." );
      return false;
    }
    creature->room()->remove( object );
    creature->add( object );
    creature->send( "You get %s.", object->shortname().c_str() );
    creature->room()->send( "$p gets $o.", creature, object );
    return true;
  }

  if ( pieces.size() == 2 ) {
    if ( ( foo = creature->findObject( pieces[1] ) ) == NULL ) {
      creature->send( "You don't see that here." );
      return false;
    }
    if ( foo->type() == OTYPE_CONTAINER ) {
      container = (ObjContainer*)foo;
    } else {
      creature->send( "That's not a container." );
      return false;
    }
    if ( container->objects().empty() ) {
      creature->send( "It's empty." );
      return false;
    }
    if ( ( object = container->find( pieces[0] ) ) == NULL ) {
      creature->send( "There's nothing like that in %s.", container->shortname().c_str() );
      return false;
    }
    container->remove( object );
    creature->add( object );
    creature->send( "You get %s out of %s.", object->shortname().c_str(), container->shortname().c_str() );
    creature->room()->send( "$p gets $o from $O.", creature, object, container );
    return true;
  }

  creature->send( syntax() );
  return false;
}

CmdGive::CmdGive( void ) {
  name( "give" );
  syntax( "syntax: give <object> <player>" );
  return;
}

bool CmdGive::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  Creature* target = NULL;
  Object* object = NULL;

  if ( pieces.size() != 2 ) {
    creature->send( syntax() );
    return false;
  }

  if ( ( target = creature->findCreature( pieces[1] ) ) == NULL ) {
    creature->send( "They're not around at the moment." );
    return false;
  }

  if ( ( object = creature->findObject( pieces[0] ) ) == NULL ) {
    creature->send( "You don't have that." );
    return false;
  }

  creature->remove( object );
  target->add( object );
  creature->send( "You give %s to %s.", object->shortname().c_str(), target->name().c_str() );
  target->send( "%s gives you %s.", creature->name().c_str(), object->shortname().c_str() );
  creature->room()->send_cond( "$p gives $c $O.", creature, target, object, TO_NOTVICT );

  return true;
}

CmdGoto::CmdGoto( void ) {
  name( "goto" );
  level( BUILDER );
  syntax( "syntax: goto <room vnum>\n        goto <mob name>\n        goto <player name>" );
  return;
}

bool CmdGoto::execute( Creature* creature, const std::string& args ) {
  estring search = Regex::trim(args);
  Creature* target = NULL;
  Room* room = NULL;
  CmdLook look;

  if ( search.empty() ) {
    creature->send( syntax() );
    return false;
  }

  if ( Regex::match( "^[0-9]+$", search ) ) {
    if ( ( room = World::Instance().findRoom( search ) ) == NULL ) {
      creature->send( "That room doesn't exist." );
      return false;
    }
  } else {
    target = World::Instance().findCreature( search );
    if ( !target || creature->canSee( target ) < SEE_NAME ) {
      creature->send( "They aren't around right now." );
      return false;
    }
    room = target->room();
  }

  if ( room == creature->room() ) {
    creature->send( "You're already there." );
    return false;
  }

  creature->room()->remove( creature );
  creature->room()->send_cond( creature->poofout(), creature );
  room->add( creature );
  room->send_cond( creature->poofin(), creature );
  creature->room( room );

  look.execute( creature, "" );

  return true;
}

CmdIdentify::CmdIdentify( void ) {
  name( "identify" );
  level( BUILDER );
  syntax( "syntax: identify <object>" );
  return;
}

bool CmdIdentify::execute( Creature* creature, const std::string& args ) {
  Object* object = NULL;
  std::string output;

  if ( args.empty() ) {
    creature->send( syntax() );
    return false;
  }

  if ( ( object = creature->findObject( args ) ) == NULL ) {
    creature->send( "You don't see that here." );
    return false;
  }

  creature->send( Object::getInformation( object ) );
  return true;
}

CmdInventory::CmdInventory( void ) {
  name( "inventory" );
  return;
}

bool CmdInventory::execute( Creature* creature, const std::string& args ) {
  std::string output;

  if ( creature->objects().empty() ) {
    creature->send( "You aren't carrying anything at the moment." );
    return true;
  }

  output.append( "You're currently holding:" );
  for ( std::list<Object*>::iterator it = creature->objects().begin(); it != creature->objects().end(); ++it ) {
    output.append( "\n " ).append( (*it)->shortname() );
  }

  creature->send( output );
  return true;
}

CmdInvisible::CmdInvisible( void ) {
  name( "invisible" );
  level( BUILDER );
  return;
}

bool CmdInvisible::execute( Creature* creature, const std::string& args ) {

  creature->admin( ADMIN_INVIS, !creature->admin( ADMIN_INVIS ) );
  if ( creature->admin( ADMIN_INVIS ) ) {
    creature->send( "You slowly disappear." );
  } else {
    creature->send( "You slowly fade into existence." );
  }

  return true;
}

CmdLock::CmdLock( void ) {
  name( "lock" );
  syntax( "syntax: lock <direction>" );
  return;
}

bool CmdLock::execute( Creature* creature, const std::string& args ) {
  Exit* exit = NULL;
  Object* key = NULL;

  if ( ( exit = creature->room()->exit( args ) ) == NULL ) {
    creature->send( "There is no door in that direction." );
    return false;
  }

  if ( !exit->flag( EFLAG_CLOSED ) ) {
    creature->send( "It's open." );
    return false;
  }

  if ( exit->flag( EFLAG_LOCKED ) ) {
    creature->send( "It's already locked." );
    return false;
  }

  if ( !exit->flag( EFLAG_LOCKABLE ) ) {
    creature->send( "You can't lock that." );
    return false;
  }

  for ( std::list<Object*>::iterator it = creature->objects().begin(); it != creature->objects().end(); ++it ) {
    if ( (*it)->vnum() == exit->key() ) {
      key = *it;
      break;
    }
  }

  if ( key == NULL || key->type() != OTYPE_KEY ) {
    creature->send( "You don't have the key." );
    return false;
  }

  exit->flag( EFLAG_LOCKED, true );
  creature->send( "You lock the door." );
  creature->room()->send_cond( "$p locked the way $e.", creature, exit );

  return true;
}

CmdLook::CmdLook( void ) {
  name( "look" );
  shortcut( "l" );
  syntax( "syntax: look\n        look in <container>" );
  return;
}

bool CmdLook::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args );
  std::string output;
  char buffer[MAX_BUFFER];
  bool has_exits = false;
  Object* foo = NULL;
  ObjContainer* container = NULL;

  if ( args.empty() ) {
    // Room name...
    if ( creature->level() >= BUILDER ) {
      sprintf( buffer, "[{g%lu{x] {%c%s{x\n", creature->room()->vnum(), creature->room()->terrain()->title(), creature->room()->name().c_str() );
    } else {
      sprintf( buffer, "{%c%s{x\n", creature->room()->terrain()->title(), creature->room()->name().c_str() );
    }
    output.append( buffer );
    // Room description...
    sprintf( buffer, "{%c%s{x\n\n", creature->room()->terrain()->description(), creature->room()->description().c_str() );
    output.append( buffer );
    // Exits...
    memset( buffer, 0, MAX_BUFFER );
    for ( register unsigned short u = 0; u < 6; ++u ) {
      if ( creature->room()->exit( u ) != NULL ) {
        // Bail if we're not supposed to see the exit...
        if ( creature->room()->exit( u )->flag( EFLAG_HIDDEN ) && creature->level() < BUILDER ) {
          continue;
        }
        has_exits = true;
        // Open brackets, parentheses, etc...
        if ( creature->room()->exit( u )->flag( EFLAG_HIDDEN ) ) {
          strcat( buffer, "{W<" );
        }
        if ( creature->room()->exit( u )->flag( EFLAG_CLOSED ) ) {
          strcat( buffer, "{R[" );
        }
        // Exit name...
        strcat( buffer, "{C" );
        strcat( buffer, Exit::name( u ) );
        // Close brackets, parentheses, etc...
        if ( creature->room()->exit( u )->flag( EFLAG_CLOSED ) ) {
          strcat( buffer, "{R]" );
        }
        if ( creature->room()->exit( u )->flag( EFLAG_HIDDEN ) ) {
          strcat( buffer, "{W>" );
        }
        strcat( buffer, " " );
      }
    }
    if ( has_exits ) {
      output.append( "[ {WExits{x: {C" ).append( buffer ).append( "{x]" );
    }
    // Objects...
    for ( std::list<Object*>::iterator it = creature->room()->objects().begin(); it != creature->room()->objects().end(); ++it ) {
      if ( creature->canSee( *it ) == SEE_NAME ) {
        output.append( "\n   " ).append( (*it)->description() );
      }
    }
    // Creatures...
    for ( std::list<Creature*>::iterator it = creature->room()->creatures().begin(); it != creature->room()->creatures().end(); ++it ) {
      if ( *it != creature && creature->canSee( *it ) == SEE_NAME ) {
        output.append( "\n " ).append( (*it)->name() ).append( " is here." );
      }
    }
    creature->send( output );
    return true;
  }

  if ( pieces.size() == 2 ) {
    if ( pieces[0] == "i" || pieces[0] == "in" ) {
      if ( ( foo = creature->findObject( pieces[1], SEARCH_CARRY | SEARCH_ROOM ) ) == NULL ) {
        creature->send( "You don't see that here." );
        return false;
      }
      if ( foo->type() == OTYPE_CONTAINER ) {
        container = (ObjContainer*)foo;
      } else {
        creature->send( "That's not a container." );
        return false;
      }
      if ( container->objects().empty() ) {
        creature->send( "There is nothing in %s.", container->shortname().c_str() );
        return true;
      }
      output.append( container->shortname().c_str() ).append( " holds:" );
      for ( std::list<Object*>::iterator it = container->objects().begin(); it != container->objects().end(); ++it ) {
        output.append( "\n  " ).append( (*it)->shortname() );
      }
      creature->send( output );
      return true;
    } else {
      creature->send( syntax() );
      return false;
    }
  }

  return false;
}

CmdMap::CmdMap( void ) {
  name( "map" );
  shortcut( "m" );
  syntax( "syntax: map" );
  return;
}

bool CmdMap::execute( Creature* creature, const std::string& args ) {
  std::string output;
  register short xsize = 36;
  register short ysize = 9;
  register short x = 0;
  register short y = 0;
  bool success = false;

  // Allocate a 2D array of Room pointers and initialize to NULL...
  Room*** map = new Room**[xsize];
  for ( y = 0; y < ysize; ++y ) {
    map[y] = new Room*[xsize];
    for ( x = 0; x < xsize; ++x ) {
      map[y][x] = NULL;
    }
  }

  // Allocate a 2D array of characters and initialize to spaces...
  char** display = new char*[ysize*2];
  for ( y = 0; y < ysize*2; ++y ) {
    display[y] = new char[xsize*2+1];
    for ( x = 0; x < xsize*2; ++x ) {
      display[y][x] = ' ';
    }
    display[y][xsize*2] = '\0';
  }

  // Start a depth-first search of the map, beginning in the current room...
  success = World::search_map( creature, map, ysize/2, xsize/2, ysize/2, xsize/2, creature->room(), display );

  // Print out our map...
  output.append( xsize*2+2, '-' ).append( 1, '\n' );
  for ( y = ysize*2-1; y > 0; --y ) {
    output.append( 1, '|' ).append( World::interpret_map_line(display[y]) ).append( "|\n" );
  }
  output.append( xsize*2+2, '-' ).append( 1, '\n' );

  if ( !success ) {
    output.append( "There was an error generating this map because the area isn't square.\nThe output may be garbled.\nPlease contact the Head Builder." );
  }

  creature->send( output );
  return true;
}

CmdMedit::CmdMedit( void ) {
  name( "medit" );
  level( BUILDER );
  syntax( "syntax: medit <vnum>\n        medit create <vnum>" );
  return;
}

bool CmdMedit::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  std::map<unsigned long,Mob*>::iterator it;
  Area* area = NULL;
  Mob* mob = NULL;
  unsigned long vnum = 0;

  if ( pieces.size() == 1 ) {
    vnum = estring(pieces[0]);
    // Get the area...
    if ( ( area = World::Instance().lookup( vnum ) ) == NULL ) {
      creature->send( "That vnum doesn't exist." );
      return false;
    }
    // Check permissions...
    if ( !World::Instance().hasPermission( area, (Avatar*)creature ) ) {
      creature->send( "You don't have permissions to that object." );
      return false;
    }
    // Make sure the Object exists...
    if ( ( it = area->mobs().find( vnum ) ) == area->mobs().end() ) {
      creature->send( "That mob doesn't exist." );
      return false;
    }
    // Make sure no one else is editing the object...
    for ( std::map<std::string,Avatar*>::iterator a_it = World::Instance().getAvatars().begin(); a_it != World::Instance().getAvatars().end(); ++a_it ) {
      if ( a_it->second->mode() == MODE_MEDIT && a_it->second->medit() == it->second ) {
        creature->send( "Sorry, %s is currently editing %s (mob %lu).", creature->seeName( ((Creature*)a_it->second) ).c_str(), it->second->name().c_str(), it->second->vnum() );
        return false;
      }
    }
    // All looks well; send them to oedit...
    creature->medit( it->second );
    creature->mode( MODE_MEDIT );
    creature->pushHandler( new MeditHandler( creature ) );
    creature->send( "You're editing mob %lu.", creature->medit()->vnum() );
    return true;
  }

  if ( pieces.size() == 2 && Regex::strPrefix( pieces[0], "create" ) ) {
    vnum = estring(pieces[1]);
    // Get the area...
    if ( ( area = World::Instance().lookup( vnum ) ) == NULL ) {
      creature->send( "That vnum doesn't exist." );
      return false;
    }
    // Check permissions...
    if ( !World::Instance().hasPermission( area, (Avatar*)creature ) ) {
      creature->send( "You don't have permissions to that mob." );
      return false;
    }
    // Make sure the Mob doesn't already exist...
    if ( ( it = area->mobs().find( vnum ) ) != area->mobs().end() ) {
      creature->send( "That mob already exists." );
      return false;
    }
    // Everything checks out; let's make us a new Mob!
    if ( ( mob = Mob::create( area, vnum ) ) == NULL ) {
      creature->send( "There was an error creating the mob." );
      return false;
    }
    creature->send( "Mob %lu created successfully.", mob->vnum() );
    creature->mode( MODE_MEDIT );
    creature->medit( mob );
    creature->pushHandler( new MeditHandler( creature ) );
    return true;
  }

  creature->send( syntax() );
  return false;
}

CmdMlist::CmdMlist( void ) {
  name( "mlist" );
  level( BUILDER );
  syntax( "syntax: mlist <areaID>\n        mlist <first vnum> <last vnum>\n        mlist <string>\n        mlist /<regex>\n  [Enclose 'search string' or '/regular expression' in quotes if it contains any spaces]" );
  return;
}

bool CmdMlist::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  std::vector<Mob*> mobs;
  Area* area = NULL;
  unsigned long low = 0;
  unsigned long high = 0;
  std::string search;
  std::string output;
  char buffer[MAX_BUFFER];

  if ( pieces.size() == 1 ) {
    if ( Regex::match( "^[0-9]+$", pieces[0] ) ) {
      // We got an areaID...
      if ( ( area = World::Instance().findArea( estring(pieces[0]) ) ) == NULL ) {
        creature->send( "That area couldn't be found." );
        return false;
      }
      for ( std::map<unsigned long,Mob*>::iterator m_it = area->mobs().begin(); m_it != area->mobs().end(); ++m_it ) {
        mobs.push_back( m_it->second );
      }
    } else {
      if ( pieces[0][0] == '/' ) {
        pieces[0].erase( 0, 1 );
        // This search is a regex...
        for ( std::set<Area*,area_comp>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it ) {
          for ( std::map<unsigned long,Mob*>::iterator m_it = (*a_it)->mobs().begin(); m_it != (*a_it)->mobs().end(); ++m_it ) {
            if ( m_it->second->matchesKeyword( pieces[0] ) ) {
              mobs.push_back( m_it->second );
            }
          }
        }
      } else {
        search = Regex::lower(pieces[0]);
        // We got a search string...
        for ( std::set<Area*,area_comp>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it ) {
          for ( std::map<unsigned long,Mob*>::iterator m_it = (*a_it)->mobs().begin(); m_it != (*a_it)->mobs().end(); ++m_it ) {
            if ( m_it->second->matchesKeyword( search ) ) {
              mobs.push_back( m_it->second );
            }
          }
        }
      }
    }
  } else if ( pieces.size() == 2 ) {
    /* We're looking for a vnum range here */
    // Grab our range values...
    low = estring(pieces[0]);
    high = estring(pieces[1]);
    // Check our range...
    if ( !high || low >= high ) {
      creature->send( "Invalid vnum range." );
      return false;
    }
    if ( low+400 < high ) {
      creature->send( "The maximum vnum range is 400." );
      return false;
    }
    // Grab the mobs...
    for ( std::set<Area*,area_comp>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it ) {
      for ( std::map<unsigned long,Mob*>::iterator m_it = (*a_it)->mobs().begin(); m_it != (*a_it)->mobs().end(); ++m_it ) {
        if ( m_it->second->vnum() >= low && m_it->second->vnum() <= high ) {
          mobs.push_back( m_it->second );
        }
      }
    }
  } else {
    creature->send( syntax() );
    return false;
  }

  if ( mobs.empty() ) {
    creature->send( "No matches for \"%s\"", pieces[0].c_str() );
    return false;
  }

  output.append( " [{y vnum{x] {gname{x\n -------------------\n" );
  for ( std::vector<Mob*>::iterator it = mobs.begin(); it != mobs.end(); ++it ) {
    sprintf( buffer, " [{y%5lu{x] %s{x\n", (*it)->vnum(), (*it)->name().c_str() );
    output.append( buffer );
  }

  creature->send( output );
  return true;
}

CmdMload::CmdMload( void ) {
  name( "mload" );
  level( BUILDER );
  syntax( "syntax: mload <vnum>" );
}

bool CmdMload::execute( Creature* creature, const std::string& args ) {
  unsigned long vnum = estring(args);
  std::map<unsigned long,Mob*>::iterator m_it;
  Mob* mob = NULL;

  if ( args.empty() ) {
    creature->send( syntax() );
    return false;
  }

  for ( std::set<Area*,area_comp>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it ) {
    if ( ( m_it = (*a_it)->mobs().find( vnum ) ) != (*a_it)->mobs().end() ) {
      mob = Mob::create( m_it->second, creature->room() );
      if ( mob == NULL ) {
        creature->send( "Mload failed. Don't you feel stupid?" );
        return false;
      }
      World::Instance().insert( mob );
      creature->room()->add( mob );
      mob->room( creature->room() );
      creature->send( "You load %s.", mob->name().c_str() );
      creature->room()->send_cond( "$p has created $c.", creature, mob );
      return true;
    }
  }

  creature->send( "There is no mob of that vnum." );
  return false;
}

CmdMoveNorth::CmdMoveNorth( void ) {
  name( "north" );
  shortcut( "n" );
  return;
}

bool CmdMoveNorth::execute( Creature* creature, const std::string& args ) {
  std::string message;
  if ( creature->canMove( NORTH, message ) ) {
    creature->move( NORTH );
    return true;
  } else {
    creature->send( message );
    return false;
  }
}

CmdMoveEast::CmdMoveEast( void ) {
  name( "east" );
  shortcut( "e" );
  return;
}

bool CmdMoveEast::execute( Creature* creature, const std::string& args ) {
  std::string message;
  if ( creature->canMove( EAST, message ) ) {
    creature->move( EAST );
    return true;
  } else {
    creature->send( message );
    return false;
  }
}

CmdMoveSouth::CmdMoveSouth( void ) {
  name( "south" );
  shortcut( "s" );
  return;
}

bool CmdMoveSouth::execute( Creature* creature, const std::string& args ) {
  std::string message;
  if ( creature->canMove( SOUTH, message ) ) {
    creature->move( SOUTH );
    return true;
  } else {
    creature->send( message );
    return false;
  }
}

CmdMoveWest::CmdMoveWest( void ) {
  name( "west" );
  shortcut( "w" );
  return;
}

bool CmdMoveWest::execute( Creature* creature, const std::string& args ) {
  std::string message;
  if ( creature->canMove( WEST, message ) ) {
    creature->move( WEST );
    return true;
  } else {
    creature->send( message );
    return false;
  }
}

CmdMoveUp::CmdMoveUp( void ) {
  name( "up" );
  shortcut( "u" );
  return;
}

bool CmdMoveUp::execute( Creature* creature, const std::string& args ) {
  std::string message;
  if ( creature->canMove( UP, message ) ) {
    creature->move( UP );
    return true;
  } else {
    creature->send( message );
    return false;
  }
}

CmdMoveDown::CmdMoveDown( void ) {
  name( "down" );
  shortcut( "d" );
  return;
}

bool CmdMoveDown::execute( Creature* creature, const std::string& args ) {
  std::string message;
  if ( creature->canMove( DOWN, message ) ) {
    creature->move( DOWN );
    return true;
  } else {
    creature->send( message );
    return false;
  }
}

